// RemoveReadOnlyContextMenuExt.h
// (c) 2008, Charles Lechasseur
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#pragma once
#include "resource.h"       // main symbols

#include "RemoveReadOnly_i.h"

#include <vector>
#include <string>
#include "Nullable.h"


#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif


//
// CRemoveReadOnlyContextMenuExt
//
// Shell contextual menu extension allowing to remove the read-only flag from a set of files.
//
class ATL_NO_VTABLE CRemoveReadOnlyContextMenuExt :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CRemoveReadOnlyContextMenuExt, &CLSID_RemoveReadOnlyContextMenuExt>,
    public IRemoveReadOnlyContextMenuExt,
    public IShellExtInit,
    public IContextMenu
{
public:
    CRemoveReadOnlyContextMenuExt()
        : m_vFiles(),
          m_FirstCmdId(),
          m_RemoveCmdId(),
          m_SetCmdId(),
          m_PredefinedFlagState()
    {
    }

    DECLARE_REGISTRY_RESOURCEID(IDR_REMOVEREADONLYCONTEXTMENUEXT)

    DECLARE_NOT_AGGREGATABLE(CRemoveReadOnlyContextMenuExt)

    BEGIN_COM_MAP(CRemoveReadOnlyContextMenuExt)
        COM_INTERFACE_ENTRY(IRemoveReadOnlyContextMenuExt)
        COM_INTERFACE_ENTRY(IShellExtInit)
        COM_INTERFACE_ENTRY(IContextMenu)
    END_COM_MAP()

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:
    // IShellExtInit methods
    STDMETHOD(Initialize)(PCIDLIST_ABSOLUTE p_pFolderPIDL, IDataObject* p_pDataObject, HKEY p_hKeyFileClass);

    // IContextMenu methods
    STDMETHOD(QueryContextMenu)(HMENU p_hMenu, UINT p_Index, UINT p_FirstCmdId,
                                UINT p_LastCmdId, UINT p_Flags);
    STDMETHOD(InvokeCommand)(CMINVOKECOMMANDINFO* p_pCommandInfo);
    STDMETHOD(GetCommandString)(UINT_PTR p_CmdId, UINT p_Flags, UINT* p_pReserved,
                                LPSTR p_pBuffer, UINT p_BufferSize);

private:
    typedef std::vector<std::wstring>   FilesV;

    FilesV                          m_vFiles;       // List of files selected in shell.

    Nullable<UINT>                  m_FirstCmdId;   // ID of first menu item command.
    Nullable<UINT>                  m_RemoveCmdId;  // ID of the "Remove" menu item command.
    Nullable<UINT>                  m_SetCmdId;     // ID of the "Set" menu item command.

    // Will be set if we must show only one command. Indicates which flag should be shown.
    Nullable<bool>                  m_PredefinedFlagState;

    void                            ModifyReadOnlyFlag(const std::wstring& p_Path,
                                                       const bool p_FlagState);
};

OBJECT_ENTRY_AUTO(__uuidof(RemoveReadOnlyContextMenuExt), CRemoveReadOnlyContextMenuExt)
